﻿using System.Collections.Immutable;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService.Symbols;

/// <summary>
///     类型符号的基类，类型符号包括：Module，Class，Interface，Enum，EnumMember。
///     这些符号名都不区分大小写，同时，只
/// </summary>
public abstract class AbstractTypeSymbol : AbstractSymbol, ITypeSymbol
{
    protected AbstractTypeSymbol(SymbolKinds symbolKind, TypeKinds typeKind) : base(symbolKind)
    {
        TypeKind = typeKind;
        NamedMembers = new DomainSymbolTable(this);
    }


    protected PropertySymbol? DefaultProperty { get; set; }
    protected MethodSymbol? DefaultMethod { get; set; }
    protected PropertySymbol? IndexerProperty { get; set; }


    internal DomainSymbolTable NamedMembers { get; }

    protected int NamedMembersCount => NamedMembers.Count;

    protected TypeSymbolModifierFlags ModifierFlags { get; set; } = TypeSymbolModifierFlags.None;

    public virtual TypeKinds TypeKind { get; }

    public virtual ITypeSymbol? BaseType => null;

    public virtual IReadOnlyList<ITypeSymbol> Interfaces => new List<ITypeSymbol>();

    public abstract IDeclaration? Declaration { get; }

    public virtual string? ContainingModuleName => ContainingModule?.FullName ?? null;

    public virtual ISymbol? ContainingModule => null;

    public virtual bool IsUnion => false;

    public virtual bool IsModule => false;

    public virtual bool IsClass => false;

    public virtual bool IsInterface => false;

    public virtual bool IsEnum => false;

    public override bool IsUndefined => false;

    public bool IsSignature => Declaration?.IsSignature ?? false;

    public virtual bool IsBindable => false;

    public virtual bool WithParameter => false;

    public bool WithConstant { get; protected set; }


    public virtual bool HasInterface(ITypeSymbol symbol)
    {
        return false;
    }

    public ImmutableArray<ISymbol> GetMembers()
    {
        return [..NamedMembers];
    }


    /// <summary>
    ///     获取指定名称的类型成员符号，此方法只在当前符号的成员符号表中查找。
    /// </summary>
    /// <param name="name">成员名，不区分大小写</param>
    public virtual ITypeSymbol? LookupNamedMember(string name)
    {
        return NamedMembers.LookupDeclaredSymbol(name) as ITypeSymbol;
    }


    public bool IsDefault => (ModifierFlags & TypeSymbolModifierFlags.Default) != 0;

    public virtual bool IsReadOnly => (ModifierFlags & TypeSymbolModifierFlags.ReadOnly) != 0;

    public bool IsWriteOnly => (ModifierFlags & TypeSymbolModifierFlags.WriteOnly) != 0;


    public ITypeSymbol? GetDefaultProperty()
    {
        ITypeSymbol? property = DefaultProperty;
        property ??= BaseType?.GetDefaultProperty();
        return property;
    }


    public ITypeSymbol? GetDefaultMethod()
    {
        ITypeSymbol? method = DefaultMethod;
        method ??= BaseType?.GetDefaultMethod();
        return method;
    }


    public ITypeSymbol? GetIndexer()
    {
        ITypeSymbol? indexer = IndexerProperty;
        indexer ??= BaseType?.GetIndexer();
        return indexer;
    }


    public virtual bool IsAssignableFrom(ITypeSymbol type)
    {
        // 一般来说，同一个类型不会声明两次，一般的对象类型直接对比引用相等即可。
        return ReferenceEquals(this, type);
    }


    /// <summary>
    ///     将当前符号声明为数组类型符号。
    /// </summary>
    /// <param name="rank">数组维度</param>
    /// <param name="boundaries">数组宽度列表</param>
    /// <returns>数组类型符号</returns>
    /// <exception cref="NotSupportedException"></exception>
    public virtual ITypeSymbol MakeArrayType(int rank, int[]? boundaries)
    {
        if (CanMakeArray)
        {
            return new ArrayTypeSymbol(this, rank, boundaries);
        }

        throw new NotSupportedException();
    }


    internal virtual bool TryAddMember(ISymbol member)
    {
        return NamedMembers.DeclareSymbol(member);
    }


    [Flags]
    protected enum TypeSymbolModifierFlags
    {
        /// <summary>
        ///     没有定义修饰符
        /// </summary>
        None = 0,

        /// <summary>
        ///     带有 Default 修饰符
        /// </summary>
        Default = 0x1,

        /// <summary>
        ///     带有 ReadOnly 修饰符
        /// </summary>
        ReadOnly = 0x4,

        /// <summary>
        ///     带有 WriteOnly 修饰符
        /// </summary>
        WriteOnly = 0x8,

        /// <summary>
        ///     带有 Nullable 修饰符
        /// </summary>
        Nullable = 0x10
    }
}